package cn.com.duiba.millionaire.center.spider.dao;

import cn.com.duiba.millionaire.center.biz.constants.DatabaseSchema;
import cn.com.duiba.wolf.spring.datasource.AutoRoutingDataSource;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.jdbc.datasource.DelegatingDataSource;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.List;

/**
 * Created by sunchangji on 2018/6/12.
 */
public abstract class SpiderBaseDao {
    @Resource(name = "spiderSqlSessionFactory")
    private SqlSessionTemplate spiderSqlSessionTemplate;

    /**
     * 获取合适的sqlSessionTemplate
     *
     * @param isForceUseMasterDataSource 是否强制使用master库,当为true时会强制使用master库,当为false时会判断当前是否正在事务中,如果是的话底层仍然会使用master库,如果不是的话会根据配置的规则按权重走主库或slave只读库.
     *                                   建议只在执行增删改sql时传入此参数为true.类似select * for update的语句实际上只在事务中有用,故如果不走事务,这样的语句有可能会被分配到只读库.所以写代码时需要注意for
     *                                   update语句一定要放在事务中.
     * @return
     */
    private SqlSessionTemplate getSqlSessionTemplate(boolean isForceUseMasterDataSource) {
        DatabaseSchema databaseSchema = chooseSchema();
        if (databaseSchema == null) {
            throw new IllegalArgumentException("please set databaseSchema in class:" + this.getClass().getName());
        }
        SqlSessionTemplate sqlSessionTemplate = null;
        switch (databaseSchema) {
            case SPIDER:
                sqlSessionTemplate = spiderSqlSessionTemplate;
                break;
            default:
                throw new IllegalArgumentException("当你看到这个报错的时候,你肯定没有配置返回恰当的sqlSessionTemplate,麻烦屈身进来配置一下吧");
        }
        DataSource ds = sqlSessionTemplate.getSqlSessionFactory().getConfiguration().getEnvironment().getDataSource();
        if (ds instanceof DelegatingDataSource) {
            ds = ((DelegatingDataSource) ds).getTargetDataSource();
        }

        if (ds instanceof AutoRoutingDataSource) {
            AutoRoutingDataSource autoRoutingDataSource = (AutoRoutingDataSource) ds;
            autoRoutingDataSource.determineCurrentLookupKeyByItSelf(isForceUseMasterDataSource);
        }

        return sqlSessionTemplate;
    }

    /**
     * 这个方法延迟到子类实现,由子类决定注入哪个sqlSessionTemplate,以使用不同的库
     *
     * @return
     */
    protected abstract DatabaseSchema chooseSchema();

    /**
     * @param statement
     * @return
     */
    public int insert(String statement) {
        return getSqlSessionTemplate(true).insert(addNameSpace(statement));
    }

    /**
     * @param statement
     * @return
     */
    public int update(String statement) {
        return getSqlSessionTemplate(true).update(addNameSpace(statement));
    }

    /**
     * @param statement
     * @param parameter
     * @return
     */
    public <T> T selectOne(String statement, Object parameter) {
        return getSqlSessionTemplate(false).selectOne(addNameSpace(statement), parameter);
    }

    /**
     * @param statement
     * @param parameter
     * @return
     */
    public int insert(String statement, Object parameter) {
        return getSqlSessionTemplate(true).insert(addNameSpace(statement), parameter);
    }

    /**
     * @param statement
     * @param parameter
     * @return
     */
    public int update(String statement, Object parameter) {
        return getSqlSessionTemplate(true).update(addNameSpace(statement), parameter);
    }

    /**
     * @param statement
     * @param parameter
     * @return
     */
    public <E> List<E> selectList(String statement, Object parameter) {
        return getSqlSessionTemplate(false).selectList(addNameSpace(statement), parameter);
    }

    /**
     * 获取mybatis命名空间
     *
     * @param method
     * @return
     */
    protected String addNameSpace(String method) {
        return getClass().getName() + "." + method;
    }

    /**
     * delete
     * @param statement
     * @return
     */
    public int delete(String statement) {
        return getSqlSessionTemplate(true).delete(addNameSpace(statement));
    }

    /**
     * delete
     * @param statement
     * @param parameter
     * @return
     */
    public int delete(String statement, Object parameter) {
        return getSqlSessionTemplate(true).delete(addNameSpace(statement),parameter);
    }

}
